/*
 * Copyright (C) 2004 Johan Maasing johan at zoom.nu Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package nu.zoom.util;

import java.io.*;
import java.net.*;
import java.security.*;
import java.util.UUID;

/**
 * Generates unique strings that for example can be used as unique ID's. <br />
 * The implementation is not optimised for speed.
 * <ol>
 * <li>Unique down to the millisecond. Digits 1-8 are are the hex encoded lower
 * 32 bits of the System.currentTimeMillis() call.</li>
 * <li>Unique across a cluster. Digits 9-16 are the encoded representation of
 * the 32 bit integer of the underlying IP address.</li>
 * <li>Unique down to the object in a JVM. Digits 17-24 are the hex
 * representation of the call to System.identityHashCode(), which is guaranteed
 * to return distinct integers for distinct objects within a JVM.</li>
 * <li>Unique within an object within a millisecond. Finally digits 25-32
 * represent a random 32 bit integer generated on every method call using the
 * cryptographically strong java.security.SecureRandom class using the SHA1PRNG
 * algorithm.</li>
 * </ol>
 * @see UUID
 * @deprecated Use {@link UUID} instead.
 * @author $Author: johan $
 * @version $Revision: 1.2 $
 */
@Deprecated
public class UniqueIDGenerator
{
	private SecureRandom randomGenerator = null;

	/**
	 * Get a new unique ID string. The string is always exactly 32 hex
	 * characters.
	 * 
	 * @return A new unique ID string.
	 */
	public String getID()
	{
		StringBuilder idBuffer = new StringBuilder();
		idBuffer.append(getRandomComponent());
		idBuffer.append(getJVMIdentityComponent());
		idBuffer.append(getNetworkComponent());
		idBuffer.append(getTimeComponent());
		return idBuffer.toString();
	}

	private String getTimeComponent()
	{
		long now = System.currentTimeMillis();
		return forceTo8Chars(Long.toHexString(now));
	}

	private String getNetworkComponent()
	{
		try {
			InetAddress localAddress = java.net.InetAddress.getLocalHost();
			byte[] rawArray = localAddress.getAddress();
			DataInputStream in = new DataInputStream(new ByteArrayInputStream(
					rawArray));
			int rawAddress = in.readInt();
			return forceTo8Chars(Integer.toHexString(rawAddress));
		} catch (Exception ex) {
			return "00000000";
		}
	}

	private String getJVMIdentityComponent()
	{
		String identityString = Integer.toHexString(System
				.identityHashCode(this));
		return forceTo8Chars(identityString);
	}

	private String getRandomComponent()
	{
		int randomNumber;
		if (randomGenerator == null) {
			try {
				randomGenerator = SecureRandom.getInstance("SHA1PRNG");
			} catch (NoSuchAlgorithmException ex) {
				randomGenerator = null;
			}
		}
		if (randomGenerator == null) {
			randomNumber = (int) Math.random();
		} else {
			randomNumber = randomGenerator.nextInt();
		}
		return forceTo8Chars(Integer.toHexString(randomNumber));
	}

	private String forceTo8Chars(String value)
	{
		String newValue = value;
		if (newValue.length() > 8) {
			newValue = newValue.substring(newValue.length() - 8);
		}
		if (newValue.length() < 8) {
			newValue = pad(newValue, 8);
		}
		return newValue;
	}

	private String pad(String valueToPad, int lengthOfResult)
	{
		StringBuilder result = new StringBuilder();
		for (int n = lengthOfResult - valueToPad.length(); n > 0; n--) {
			result.append("0");
		}
		result.append(valueToPad);
		return result.toString();
	}

	public static void main(String[] args)
	{
		UniqueIDGenerator uniqueIDGenerator = new UniqueIDGenerator();
		long startTime = System.currentTimeMillis();
		for (int n = 0; n < 1000; n++) {
			uniqueIDGenerator.getID();
		}
		long time = System.currentTimeMillis() - startTime;
		System.out.println("1000 GUIDS generated in " + time + " ms");
		System.out.println("Avarage " + time / 1000 + " ms / GUID");
	}

}